package io.api.modules.project.controller;

import cn.hutool.core.io.file.FileNameUtil;
import com.google.common.io.ByteStreams;
import io.admin.common.constant.Constant;
import io.admin.common.exception.ErrorCode;
import io.admin.common.exception.RenException;
import io.admin.common.page.PageData;
import io.admin.common.utils.FileUtil;
import io.admin.common.utils.Result;
import io.admin.common.utils.StringUtils;
import io.admin.common.validator.AssertUtils;
import io.admin.common.validator.ValidatorUtils;
import io.admin.common.validator.group.AddGroup;
import io.admin.common.validator.group.DefaultGroup;
import io.admin.common.validator.group.UpdateGroup;
import io.api.annotation.Pass;
import io.api.modules.project.dto.FileUrlDTO;
import io.api.modules.project.service.FileUrlService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

import static dm.jdbc.util.DriverUtil.log;


/**
 * 文件地址管理表
 *
 * @author Mark sunlightcs@gmail.com
 * @since 1.0.0 2024-07-12
 */
@RestController
@RequestMapping("/api/file")
@Api(tags="文件地址管理表")
public class FileUrlController {

    @Value("${file.user.path}")
    private String ADDRESS_FILE;

    @Autowired
    private FileUrlService fileUrlService;

    @GetMapping("page")
    @ApiOperation("分页")
    @ApiImplicitParams({
        @ApiImplicitParam(name = Constant.PAGE, value = "当前页码，从1开始", paramType = "query", required = true, dataType="int") ,
        @ApiImplicitParam(name = Constant.LIMIT, value = "每页显示记录数", paramType = "query",required = true, dataType="int") ,
        @ApiImplicitParam(name = Constant.ORDER_FIELD, value = "排序字段", paramType = "query", dataType="String") ,
        @ApiImplicitParam(name = Constant.ORDER, value = "排序方式，可选值(asc、desc)", paramType = "query", dataType="String")
    })

    public Result<PageData<FileUrlDTO>> page(@ApiIgnore @RequestParam Map<String, Object> params){
        PageData<FileUrlDTO> page = fileUrlService.page(params);

        return new Result<PageData<FileUrlDTO>>().ok(page);
    }

    @GetMapping("{id}")
    @ApiOperation("信息")
    public Result<FileUrlDTO> get(@PathVariable("id") Long id){
        FileUrlDTO data = fileUrlService.get(id);

        return new Result<FileUrlDTO>().ok(data);
    }

    @PostMapping
    @ApiOperation("保存")
    public Result save(@RequestBody FileUrlDTO dto){
        //效验数据
        ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);

        fileUrlService.save(dto);

        return new Result();
    }

    @PutMapping
    @ApiOperation("修改")
    public Result update(@RequestBody FileUrlDTO dto){
        //效验数据
        ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);

        fileUrlService.update(dto);

        return new Result();
    }

    @DeleteMapping("{id}")
    @ApiOperation("删除")
    public Result delete(@PathVariable Long id){
        fileUrlService.deleteById(id);
        return new Result();
    }

    @DeleteMapping("batch")
    @ApiOperation("删除")
    public Result delete(@RequestBody Long[] ids){
        //效验数据
        AssertUtils.isArrayEmpty(ids, "id");

        fileUrlService.delete(ids);
        return new Result();
    }

    @PostMapping("upload/local")
    @ApiOperation(value = "上传文件")
    public Result<Map<String, Object>> uploadByLocal(@RequestParam("file") MultipartFile file) throws Exception {
        String url= "";
        if (file.isEmpty()) {
            return new Result<Map<String, Object>>().error(ErrorCode.UPLOAD_FILE_EMPTY);
        }
        //上传文件
        String suffix = FileNameUtil.getSuffix(file.getOriginalFilename());
        try {
            // 获取文件名
            String ext = FileUtil.checkFileSuffix(file.getInputStream(), file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase());
            //不合法文件类型暴力返回空
            if (StringUtils.isEmpty(ext)) {
                log.info("非法文件类型");
                return new Result<Map<String, Object>>().error(10001,"无效文件");
            }
            String uuid = UUID.randomUUID().toString().replaceAll("-", "");
            String fileName = uuid + "." + ext;
            File fileIs = new File(ADDRESS_FILE);
            if(!fileIs.exists()){
                boolean created = fileIs.mkdirs();
            }
            // 获取文件的字节
            byte[] bytes = file.getBytes();
            //文件路径
            String fileNamePath = ADDRESS_FILE+fileName;
            // 使用文件名在服务器端创建文件
            Path path = Paths.get(fileNamePath);
            // 写入文件到服务器的指定目录
            Files.write(path, bytes);
            FileUrlDTO fileUrlDTO =new FileUrlDTO();
            fileUrlDTO.setId(ThreadLocalRandom.current().nextLong());
            fileUrlDTO.setUrl(fileName);
            fileUrlService.save(fileUrlDTO);
            Map<String,Object> map = new HashMap<>();
            map.put("url", fileName);
            map.put("fileId", fileUrlDTO.getId());
            return new Result<Map<String, Object>>().ok(map);

        } catch (Exception e) {
            e.printStackTrace();
            return new Result<Map<String, Object>>().error(ErrorCode.NOT_NULL,"文件上传失败");
        }
    }

    @Pass
    @GetMapping("download/local/{filename}")
    @ApiOperation(value = "文件下载")
    public ResponseEntity downloadLocal(@PathVariable("filename") String filename, HttpServletResponse response) throws Exception {
        //根据拿到的数据开始下载
//        Resource resource = resourceLoader.getResource("file:" + ADDRESS_FILE + filename);

        FileSystemResource resource = new FileSystemResource(ADDRESS_FILE + filename);
        if (resource.exists()) {
            Path path = resource.getFile().toPath();
            String mimeType = Files.probeContentType(path);
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
                    .header(HttpHeaders.CONTENT_TYPE, mimeType)
                    .body(response);
        } else {
            throw new RenException("找不到对应文件");
        }
    }

    @Pass
    @GetMapping("preview/{id}")
    @ApiOperation("信息")
    public ResponseEntity preview(@PathVariable("id") Long id) throws IOException {
        FileUrlDTO data = fileUrlService.get(id);
//        Resource resource = resourceLoader.getResource("file:" + ADDRESS_FILE + data.getUrl());
        FileSystemResource resource = new FileSystemResource(ADDRESS_FILE + data.getUrl());
        if (resource.exists()) {
            Path path = resource.getFile().toPath();
            String mediaType = Files.probeContentType(path);
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, mediaType)
                    .body(new InputStreamResource(resource.getInputStream()));
        } else {
            throw new RenException("找不到对应文件");
        }
    }

}